//
// @Auther: by wujehy 
// @Email:wujehy@qq.com
// @Data:2019/10/08
// @Time:10:33 上午
//
//

#include "SqliteAuthPlugin.h"
#include "mosquitto.h"
#include <iostream>
#include <Logger.h>
#include <mosquitto_broker.h>
#include "mosquitto_plugin.h"
#include "crud_tools.h"
#include "AclDB.h"
#include "UserDB.h"
int SqliteAuthPlugin::checkUser(const std::string &username, const std::string &password)
{
    gDebug << "SqliteAuthPlugin::checkUser username = " << username << " password = " << password;
    // TODO 差库
    if (userDb == nullptr )
    {
        return PLUGIN_ERR_TYPE::PLUGIN_UNKNOWN;
    }

    if (userDb->exist(username,password))
    {
        return PLUGIN_SUCCESS;
    }
    return PLUGIN_ERR_TYPE::PLUGIN_AUTH_DENIED;
}

SqliteAuthPlugin::SqliteAuthPlugin()
{
    std::cerr << " init SqliteAuthPlugin " << std::endl;
}

int SqliteAuthPlugin::getPskKey(mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len)
{
    gDebug << " SqliteAuthPlugin::getPskKey , hint = " << hint << " ,identity = " << identity << " key = " << " max_key_len = " << max_key_len;
    return PLUGIN_DEFER;
}

int SqliteAuthPlugin::checkAcl(mosquitto *client, ACLTypeEnum access, const mosquitto_acl_msg *msg)
{
    gDebug << " SqliteAuthPlugin::checkAcl , access = " << access << " ,qos = " << msg->qos << " topic = " << msg->topic;
    if (aclDb == nullptr)
    {
        return PLUGIN_ACL_DENIED;
    }

    int dbStatus = 0 ;
    int ret = aclDb->getTopicStatus(mosquitto_client_username(client), msg->topic , dbStatus );

    if (ret < 0 )
    {
        return PLUGIN_ACL_DENIED;
    }
    gDebug<<" dbStatus  = " << dbStatus << " access = " <<access;
    //权限判断
    if ((dbStatus & access) == access )
    {
        gDebug<<"checkAcl success ";
        return PLUGIN_SUCCESS;
    }else
    {
        gDebug<<"checkAcl fail ";
        return PLUGIN_ACL_DENIED;
    }
}

int SqliteAuthPlugin::cleanupSecurity(mosquitto_opt *auth_opts, int auth_opts_count, bool reload)
{
    gDebug << " SqliteAuthPlugin::cleanupSecurity : reload =" << reload;

    return 0;
}

int SqliteAuthPlugin::initSecurity(mosquitto_opt *auth_opts, int auth_opts_count, bool reload)
{
    gDebug << " SqliteAuthPlugin::initSecurity : reload =" << reload;

    return 0;
}

void SqliteAuthPlugin::init()
{
    db_mutex.lock();

    auto dbConfigDbName = this->m_configMap.find("db_path");

    if (!dbConfigDbName->second.empty())
    {
        this->baseName = dbConfigDbName->second;
    }

    if (m_sys_database == nullptr)
    {
        m_sys_database = new SQLite::Database(this->baseName, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE, 2000);
        aclDb = new AclDB(m_sys_database);

        userDb = new UserDB(m_sys_database);

    }

    db_mutex.unlock();

    aclDb->init();
    userDb->init();

    // TODO wujehy 测试数据 , mqtt 只有这些用户可以登录时, 可以修改数据自行增减
    userDb->add("user1", "password1");
    userDb->add("user2", "password2");
    userDb->add("user3", "password3");
    userDb->add("user4", "password4");

    // 用户1 可以随便操作 topic1
    aclDb->add("user1" , "topic1" , ACLTypeEnum::ACL_ALL );
    // 用户2 可以发送 topic1 给 其他人 , 但他订阅不了这个topic
    aclDb->add("user2" , "topic1" ,ACLTypeEnum::ACL_WRITE );
    // 用户3 可以接受 topic1 的消息, 但是发送 不了
    aclDb->add("user3" , "topic1" , ACLTypeEnum::ACL_READ|ACL_SUBSCRIBE);
    // 用户4 可以 完全控制 topic2 ,  但是不能 与 topic1 有任何关系
    aclDb->add("user4" , "topic2" , ACLTypeEnum::ACL_ALL);
}

SqliteAuthPlugin::~SqliteAuthPlugin()
{
    gDebug<<" delete userDb";

    if (userDb != nullptr)
    {
        delete userDb;
        userDb = nullptr;
    }
    gDebug<<" delete aclDb";
    if (aclDb != nullptr)
    {
        delete aclDb;
        aclDb = nullptr;
    }
    gDebug<<" delete m_sys_database";
    if (m_sys_database != nullptr)
    {
        delete m_sys_database;
        m_sys_database = nullptr;
    }
}
